# This file is intended to be a final submission. python tester.py Player.py
# should work at all times. If it does not, there is a bug.
# If you're just trying to test a solution, scroll down to the Player
# class.

# This file is intended to be in the same format as a valid solution, so
# that users can edit their solution into Player and then submit just this
# file to the contest. If you see any reason this would not work, please submit
# an Issue to https://github.com/ChadAMiller/hungergames/issues or email me.

# You can see more sample player classes in bots.py
import math

class BasePlayer(object):
    '''
    Base class so I don't have to repeat bookkeeping stuff.
    Do not edit unless you're working on the simulation.
    '''
    
    def __str__(self):
        try:
            return self.name
        except AttributeError:
            # Fall back on Python default
            return super(BasePlayer, self).__repr__()
    
    def hunt_choices(*args, **kwargs):
        raise NotImplementedError("You must define a strategy!")
        
    def hunt_outcomes(*args, **kwargs):
        pass
        
    def round_end(*args, **kwargs):
        pass


class Player(BasePlayer):
    '''
    With a pay-off matrix
		2
            h       s
         _______________
      h | +0,+0 | -3,+1 |
    1   |---------------|
      s | +1,-3 | -2,-2 |
         ---------------

    the Hunger Games is clearly a reformulated version of the Prisoner's
    Dilemma. While mutual defection is the only strong Nash Equilibrium in the 
    Prisoner's Dilemma, in the iterated scenario tit-for-tat strategies 
    work surprisingly well (http://www.brembs.net/ipd/tft.html). Historian keeps
    track of the reputation-action pairs from the previous round and mirrors
    the move of the player with the closest reputation.
    '''
    
    def __init__(self):
	self.name = "Historian"
	self.history = []
	self.reputations = []
	self.round = 0
	self.num_players = 0

    # make_prediction looks at the history of responses from the previous round and makes a
    # 1-nearest neighbor prediction of the next action of a player with a given reputation.
    # As time progresses, player reputations become less variable and serve as form of
    # identification.
 
    def make_prediction(self, reputation):
	i = 0
	best = 1
	prediction = 'h'
	for i in range(len(self.history)):
		diff = math.fabs(self.history[i][0]-reputation)
		if diff < best:
			best = diff
			prediction = self.history[i][1]
	return prediction
			
    def hunt_choices(
                    self,
                    round_number,
                    current_food,
                    current_reputation,
                    m,
                    player_reputations,
                    ):
	choices = []
	self.round = round_number
	self.reputations = player_reputations
	self.num_players = len(player_reputations)

	#At the start of the game, no player has a reputation. Historian sets its 
	#reputation to 1.0 to signal a willingness to cooperate.

	if self.round == 1:	
		choices = ['h']*(self.num_players)

	#After the first round, it is still impossible to tell who hunted and who
	#slacked. However, because moves selected during the first round are necessarily
	#targeted at random, Historian uses reputation as a maximum likelihood estimator
	#of their previous action.

	elif self.round == 2:
		for i in range(self.num_players):
			if player_reputations[i] >= .5:	
				choices.append('h')
			else:	
				choices.append('s')

	#After Round 2, Historian proceeds with the tit-for-tat approach (see description
	#of make_prediction).

        else:	
		for i in range(len(player_reputations)):
			prediction = self.make_prediction(player_reputations[i])
			choices.append(prediction)
	return choices
	
    #hunt_outcomes updates Historian's recorded history.

    def hunt_outcomes(self, food_earnings):
	self.history = []
	for i in range(len(food_earnings)):
		if food_earnings[i] == 0 or food_earnings[i] == 1:
			self.history.append([self.reputations[i],'h'])	        
		else:
			self.history.append([self.reputations[i],'s'])	       

    def round_end(self, award, m, number_hunters):
        pass
        
